let localOcr = require('./lib/LocalOcrUtil.js')
let singletonRequire = require('./lib/SingletonRequirer.js')(runtime, this)
let commonFunctions = singletonRequire('CommonFunction')
/**
 * 获取状态栏高度
 *
 * @returns
 */
function getStatusBarHeightCompat () {
    let result = 0
    let resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android")
    if (resId > 0) {
      result = context.getResources().getDimensionPixelOffset(resId)
    }
    if (result <= 0) {
      result = context.getResources().getDimensionPixelOffset(R.dimen.dimen_25dp)
    }
    return result
}
function Util() {
    this.pkgName = 'com.jingdong.app.mall'    
    this.barHeight = 0
    this.img = 0
    this.logEnable = 0
    this.floaty = null
    this.storage = storages.create("jd_util");
    this.notifyMsg = ''
    this.pushPlusToken = ''
    this.findTextDescMatchesTimeout = function (reg, timeout) {
        let c = 0
        let result = 0
        let tp = typeof reg
        if (!reg) return null
        while (c < timeout / 50) {
            if (this.logEnable) this.logInfo(c)
            if (tp == 'string') {
                result = textContains(reg).findOnce() || desc(reg).findOnce()
            } else if (tp == 'function') {
                result = reg()
            } else {
                result = textMatches(reg).findOnce() || descMatches(reg).findOnce()
            }
            if (result) return result
            sleep(50)
            c++
        }
        return null
    }
    this.findOnec = function(regx) {
        return textMatches(regx).findOnce() || descMatches(regx).findOnce()
    }
    this.allText = function(ele, loop) {
        if (!ele.text) {
            return ele
        }
        let txt = ele.text() || ''
        ele.children().forEach(item => {
            let b = this.allText(item, 1)
            if (b) {
                if (txt) txt += ' '
                txt += b
            }
        })
        txt = (!loop && txt) ? txt + '\n':txt
        return txt
    }
    this.appendNotifyMsg = function(ele, allChild) {
        allChild = allChild===undefined ? true:allChild
        let obj = this.storageOp('notifyMsg', false)
        if (!this.notifyMsg && obj && obj.msg) {
            this.pushplus('上次任务进展', obj.msg, this.pushPlusToken)
        }
        if (allChild) {
            this.notifyMsg += this.allText(ele)
        } else {
            let txt = ele.text() || ''
            ele.children().forEach(item => {
                let b = item.text()
                if (b) {
                    if (txt) txt += ' '
                    txt += b
                }
            })
            if (txt) txt += '\n';
            this.notifyMsg += txt
        }
        this.storageOp('notifyMsg', true, { msg: this.notifyMsg })
    }
    this.openApp = function (pkg, msg) {
        pkg = pkg || this.pkgName
        msg = msg || /首页/
        if(this.findTextDescMatchesTimeout(msg, 2000)) return
        let obj = this.findTextDescMatchesTimeout(/.*/, 1000)
        if (!obj || obj.packageName().indexOf(pkg) < 0){
            this.logInfo('正在打开App...', pkg)
            if (!launch(pkg)) {
                this.logInfo('可能未安装App:', pkg)
            }
            if (device.model == 'Redmi Note 4X' && pkg.indexOf('jingdong') > -1) {
                let aaa = '/' + app.getAppName(pkg) + '/'
                this.clickText(eval(aaa))
            }
            this.findTextDescMatchesTimeout(msg, 20000)
        }
    }
    this.openAndInto = function (txt, pkg, realOpen, errTxt) {
        if (realOpen) this.openApp(pkg, txt)
        this.backToText(txt||/首页/)
        if (!txt) {
            this.logInfo('进入活动页面')
            return
        }
        if (errTxt) {
            if (this.findTextDescMatchesTimeout(errTxt, 1000)) {
                return errTxt
            }
            let region = [0, device.height*0.6, device.width, device.height*0.4]
            if (this.clickTextOcr(txt, region)) {
                return errTxt
            }
            this.logInfo('未找到', errTxt)
        }
        return this.clickText(txt)
    }
    this.getTitle = function () {
        let ele = idContains('fb').findOnce()
        if (!ele) {
            ele = this.findOnec(/返回/)
            ele = ele?ele.parent().parent():null
        }
        let a = 16
        let b = 65
        let c = 1064
        let d = 202
        if (ele) {
            a = ele.bounds().left
            b = ele.bounds().top
            c = ele.bounds().right
            d = ele.bounds().bottom
            a = a>0?a-1:0
            b = b>0?b-1:0
            c = c<device.width?c+1:c
            d = d<device.height?d+1:d
        }
        let lst = textMatches(/.*/).boundsInside(a,b, c,d).find()
        let txt = ''
        if (!lst) return txt
        lst.forEach(element => {
            if (txt) {
                txt += '/'
            }
            txt += element.text()
        });
        this.logInfo('getTitle', txt)
        return txt
    }
    this.ocrImgInPath = function (txt, path, region, clickIt) {
        if (!this.barHeight) {
            this.barHeight = getStatusBarHeightCompat()
        }
        if (!path) return
        let img = images.read(path)
        if (!img ) {
          toastLog('截图失败')
          return false
        }
        let ret = this.ocrImage(txt, img, region, clickIt)
        this.logInfo('remove', path, files.remove(path))
        return ret
    }
    this.ocrImage = function(txt, image, region, clickIt) {
        this.img && this.img.recycle()
        this.img = image
        let delay = 1000
        clickIt = clickIt === undefined?true:clickIt
        region = region||[0,0,device.width,device.height]
        let result = localOcr.recognizeWithBounds(this.img, region, txt)
        if (result && result.length > 0) {
          let collect = result[0].bounds
          this.logInfo(`OCR找到了目标 ${txt}: ${result[0].label}`)
          if (clickIt) {
            return this.click(collect.centerX(), collect.centerY(), result[0].label)
          }
        }
        return false
    }
    this.getTextByOcr = function(txt, image, region, clickIt) {
        this.img && this.img.recycle()
        this.img = image
        let delay = 1000
        clickIt = clickIt === undefined?true:clickIt
        region = region||[0,0,device.width,device.height]
        let result = localOcr.recognizeWithBounds(this.img, region, txt)
        if (result && result.length > 0) {
          return result[0]
        }
        return null
    }
    this.backToText = function (text, pkgName) {
        let timeout = 2000
        let ret = false
        let title = this.getTitle()
        let d = new Date()
        let t = d.getTime()
        for (let i=0;i<8; ++i) {
            if (this.isMainPage()) {
                this.logInfo('已经在首页')
                break
            }
            d = new Date()
            if ((d.getTime() - t) > (1.5*60*1000)) {
                this.logInfo('等待时长', d.getTime() - t)
                recents()
                sleep(2000)
                back()
                t = d.getTime()
            }
            let renwu = this.findTextDescMatchesTimeout(text, timeout)
            if (!renwu) {
                let t = this.getTitle()
                this.logInfo('无法找到', text, '返回')
                let cpkg = currentPackage()
                let tmsg = this.getNotification()
                back()
                if ((i>4 && ((title && t==title) || (cpkg && cpkg.indexOf(pkgName) < 0))) || tmsg=='再按一次退出') {
                    this.logInfo('双击返回', cpkg, pkgName, t, tmsg)
                    sleep(400)
                    back()
                    this.getNotification()
                }
                this.closeDialogByImage()
            } else {
                ret = true
                this.logInfo('找到', text, renwu.text())
                break
            }
        }
        return ret
    }
    this.isMainPage = function() {
        let mainPage = null
        let ele = idMatches(/.+\..+/).findOnce()
        if (ele && ele.id().indexOf('jingdong') >= 0) {
            mainPage = [/首页/,/我的/,/购物车/]
        }
        if (ele && ele.id().indexOf('jrapp') >= 0) {
            mainPage = [/去看看/,/我的/]
        }
        if (mainPage) {
            let find = true
            for (let ndx = 0; ndx < mainPage.length; ++ndx) {
                let renwu = this.findTextDescMatchesTimeout(mainPage[ndx], 1000)
                if (!renwu) {
                    find = false
                    break
                }
            }
            return find
        }
        return false
    }
    this.backToApp = function (pkg) {
        if (!pkg) return true
        let i = 5
        while (i--) {
            let ids = ''
            let ele = idContains(pkg).findOnce()// || idMatches(/([^\.]+\.?){3,10}/).findOnce() || idMatches(/([^\.]+\.?){2,10}/).depth(4).findOnce()
            if (ele) ids = ele.id()
            if (ids.indexOf(pkg) >= 0 || currentPackage().indexOf(pkg) >= 0) {
                return true
            }
            this.logInfo('want:', pkg, 'curr:', ids, currentPackage())
            back()
            sleep(500)
            back()
            sleep(2000)
            break
        }
        return i
    }
    this.taskCount = {}
    this.getTasksByText = function (txt, ignores, textFinder, white) {
        let tButton = null,
            tText = '',
            tCount = 0,
            tTitle = ''
        let taskButtons = textMatches(txt).find()
        this.logInfo('寻找未完成任务...', taskButtons.length)
        if (!taskButtons.empty()) { // 如果找不到任务，直接返回
            for (let i = 0; i < taskButtons.length; i++) {
                let button = taskButtons[i]
                let lst = []
                if (textFinder) {
                    try {
                        textFinder(button, lst)
                    } catch (err) {
                        this.logInfo('查找任务异常', err)
                        continue
                    }
                } else {
                    let rect = {top: button.bounds().top-55, left: 0, bottom: button.bounds().bottom+55, right: device.width}
                    let ttt = this.boundsInsideText(rect, /.*/)
                    if (ttt) {lst.push(ttt) }
                    else {
                        rect = [button.bounds().top-55, 0, device.width, button.bounds().bottom+55]
                        rect = this.getTextByOcr(/.*/, commonFunctions.captureScreen(), rect)
                        if (rect) {
                            lst.push(rect.label)
                        }
                    }
                }
                if (lst.length == 0) {
                    this.logInfo('task text len=0', i)
                    continue
                }
                tTitle = lst[0]
                if (lst.length > 1) tText = lst[1]
    
                let r = tTitle.match(/(\d)\/(\d+)/) || tText.match(/(\d)\/(\d+)/)
                if (r) {
                    tCount = (r[2] - r[1])
                } else {
                    tCount = 0
                }
    
                let filted = false
                if (ignores) {
                    for (let ndx = 0; ndx < ignores.length; ++ndx) {
                        filted = tText.match(ignores[ndx]) || tTitle.match(ignores[ndx])
                        if (filted) {
                            filted = true
                            break
                        }
                        filted = false
                    }
                }
                if (white && !filted) {
                    for (let ndx = 0; ndx < white.length; ++ndx) {
                        r = tText.match(white[ndx]) || tTitle.match(white[ndx])
                        if (!r) {
                            filted = true
                        }
                    }
                }
                let maxCount = tCount==0?10:tCount+1
                if (!filted && this.taskCount[tTitle] > maxCount) {
                    filted = true
                }
                // if (!find && !this.validBounds(button)) {
                //     find = true
                // }
                this.logInfo('任务:', button.text(), tTitle, tCount, filted)
                if (filted) continue 
                tButton = button
                break
            }
        } else {
            this.logInfo('任务提示未找到')
        }
        if (tButton)
        this.taskCount[tTitle] = ((this.taskCount[tTitle]||0) + 1)
        return [tButton, tText, tCount, tTitle]
    }
    this.clickElement = function (ele, type) {
        if (!ele) return
        type=type||3
        let a=0
        this.setFloatyInfo({x:ele.bounds().centerX(),y:ele.bounds().centerY()}, ele.text())
        if (type&1) {
            let txt = ele.text()
            a=ele.click()
            sleep(1000)
            if (a) {
                let b = this.findTextDescMatchesTimeout(txt, 500)
                if (!b || !b.visibleToUser() || !this.sameRect(ele.bounds(), b.bounds())) {
                    this.logInfo('by click')
                    return a
                }
            }
        }
        if ((type&2) && ele.visibleToUser() && this.validBounds(ele, 1)) {
            this.logInfo(ele.bounds().centerX(), ele.bounds().centerY())
            click(ele.bounds().centerX(), ele.bounds().centerY())
            return true
        }
        return a
    }
    this.storageOp = function(k, isPut, v) {
        if (isPut) {
            this.storage.put(k, JSON.stringify(v))
        } else {
            let s = this.storage.get(k,v)
            if (s) {
                return JSON.parse(s)
            }
            return s
        }
    }
    this.clickText = function (txt, timeoutOrAfterTxt, boundType, addon, cache) {
        let tp = typeof timeoutOrAfterTxt
        let timeout = 10000
        let afterTimeout = 3000
        let afterTxt = null
        if (tp == 'number') {
            timeout = timeoutOrAfterTxt
        } else if ((timeoutOrAfterTxt instanceof Array)) {
            timeout = timeoutOrAfterTxt[0] || timeout
            afterTxt = timeoutOrAfterTxt[1] || afterTxt
            afterTimeout = timeoutOrAfterTxt[2] || afterTimeout
            // this.logInfo(txt, timeout, afterTimeout, afterTxt)
        } else {
            afterTxt = timeoutOrAfterTxt
        }
        let x=0,y=0
        if (cache) {
            let lst = this.storageOp(txt, false)
            if (lst) {
                x = lst[0]
                y = lst[1]
            }
        }
        let renwu = this.findTextDescMatchesTimeout(txt, timeout)
        if (!renwu && x === 0) {
            this.logInfo('未找到', txt, timeoutOrAfterTxt)
            renwu = this.findTextDescMatchesTimeout(/.*没有响应/, 1000)
            if (renwu) {
                renwu = this.findTextDescMatchesTimeout(/确定/, 1000)
                this.clickElement(renwu)
            }
            return false
        }
        let r = false
        if (renwu) {
            if (!boundType) {
                this.logInfo('点击', txt, renwu.text())
                r = this.clickElement(renwu)
                this.storageOp(txt, true, [renwu.bounds().centerX(), renwu.bounds().centerY()])
            } else if (boundType == 1) {
                x=renwu.bounds().left
                y=renwu.bounds().top
            } else if (boundType == 2) {
                x=renwu.bounds().centerX()
                y=renwu.bounds().centerY()
            } else if (boundType == 3) {
                x = renwu.bounds().right
                y = renwu.bounds().bottom
            } else if (boundType == 4) {
                r = this.clickElement(renwu, 1)
            } else if (boundType == 5) {
                r = this.clickElement(renwu, 2)
            }
            if (addon && addon.length > 1) {
                x = x + addon[0]
                y = y + addon[1]
            }
            if (cache && boundType !== undefined)
                this.storageOp(txt, true, [x, y])
        }
        if (x && y) {
            this.logInfo('点击', txt, x, y, renwu?renwu.text():'')
            r = click(x, y)
            this.setFloatyInfo({x,y}, txt)
        }
        if (afterTxt) {
            renwu = this.findTextDescMatchesTimeout(afterTxt, afterTimeout)
            afterTimeout = 2000
        }
        sleep(afterTimeout)
        return r
    }
    this.validBounds = function (ele, type) {
        type = type || 3
        if (type&1) {
            if (ele.bounds().centerX() < 0) {
                return false
            }
            if (ele.bounds().centerY() < 0) {
                return false
            }
        }
        if (type&2) {
            if (ele.bounds().centerX() > device.width) {
                return false
            }
            if (ele.bounds().centerY() > device.height) {
                return false
            }
        }
        return true
    }
    this.sameRect = function (rect1, rect2) {
        return (rect1.top == rect2.top && 
          rect1.left == rect2.left && 
          rect2.right == rect1.right && 
          rect1.bottom == rect2.bottom)
    }
    this.closeDialog = function(regx, timeout, x, y) {
        if (this.closeDialogByImage()) return
        timeout = timeout || 2000
        const times = 40
        cnt = times
        x= x || (device.width-80)
        y= y || 100
        let sub = 50
        while (cnt--) {
            let ele = this.findTextDescMatchesTimeout(regx, timeout)
            if (ele) {
                this.logInfo('dialog pos:', x, y)
                this.setFloatyInfo(null, 'X')
                click(x, y)
                this.setFloatyInfo({x,y}, 'X')
                if (y + sub > device.height) {
                    sub = 0-sub
                }
                if (y + sub < 0) {
                    break
                }
                y+=sub
                sleep(500)
                if (cnt ==0 && this.findTextDescMatchesTimeout(regx, timeout)) {
                    cnt = times
                    y = 100
                }
                continue
            }
            break
        }
        return cnt < times-1
    }
    this.closePopup = function(text, close, x, y) {
        if (this.closeDialogByImage()) return

        let timeout = 1000
        let ele = this.findTextDescMatchesTimeout(text, timeout)
        if (!ele) return
        y = device.height - 10       
        this.setFloatyInfo({x:ele.bounds().left, y:ele.bounds().bottom}, text)
        let lst = className('TextView').text('').clickable().find()
        if (lst.length > 0) {
            this.logInfo('closePopup close len:', lst.length)
            this.clickElement(lst[0], 1)
            return
        }
        if (!x && !y) return
        this.closeDialog(text, timeout,  x, y)
    }
    this.clickTextOcr = function(text, rect) { // 识别文字并点击
        try {
            let pos = this.getTextByOcr(text, commonFunctions.captureScreen(), rect, true)
            if (pos) {
                this.logInfo('识别到文字:', text)
            }
            return pos
        } catch (error) {
            this.logInfo('识别文字失败:', error)
        }
        return null
    }
    this.closeDialogByImage = function(txt) {
        txt = txt || /离开.*|.*?关闭.*/
        let sub = 50
        let left = device.width/2 - sub
        let top = 0
        let right = device.width/2 + sub
        let bottom = device.height
        let rects = [[left, top, right, bottom]]
        sub = 100
        rects.push([device.width - sub, 0, device.width, device.height])
        let find = false
        for (pos of rects) {
            let lst = classNameContains('Image').boundsInside(pos[0], pos[1], pos[2], pos[3]).find()
            lst.forEach(element => {
                let rect = element.bounds()
                sub = Math.abs(rect.width() - rect.height())
                if (sub > 10) {
                    return
                }
                this.setFloatyInfoEle(element, 'close button')
                find = true
                rect = (element.parent()||element).bounds()
                let region = [rect.left, rect.top, rect.right, rect.bottom]
                if (this.clickText(txt, 1000) || this.clickTextOcr(txt, region)) {
                } else { 
                    this.clickElement(element, 3)
                }
            });
            if (find) break
        }
        return find
    }
    this.innerlog = function(msg) {
        console.log(msg)
    }
    this.logInfo = function(p1,p2,p3,p4,p5) {
        let lst = [p1,p2,p3,p4,p5]
        let msg = ''
        for (let i=0;i<lst.length;++i) {
            p1 = lst[i]
            if (p1 == undefined) {
                break
            }
            if (msg) msg += ' '
            msg += p1
        }
        if (msg) 
            this.innerlog(msg)
    }
    this.qywxBotNotify = function (text, desp, QYWX_KEY) {
        let url = `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${QYWX_KEY}`
        let data = {
            msgtype: 'text',
            text: {
                content: ` ${text}\n\n${desp}`,
            }
        }
        const options = {
            headers: {
            'Content-Type': 'application/json',
            }
        };
        let rsp = http.postJson(url, data, options)
        if (rsp.statusCode == 200) {
            this.logInfo('企业微信发送通知消息成功🎉。');
        } else {
            this.logInfo('企业微信发送通知消息失败！！', rsp.body.string());
        }
    }
    this.wxpusher = function(title, content, token) {
        let url = `https://wxpusher.zjiecode.com/api/send/message`
        let data = {
            appToken: token.split('/')[0],
            content,
            summary: title,
            contentType: 1,
            uids: [token.split('/')[1]],
            verifyPay: false,
            verifyPayType: 0
        }
        const options = {
            headers: {
            'Content-Type': 'application/json',
            }
        };
        let rsp = http.postJson(url, data, options)
        console.log(rsp.body.string())

    }
    this.pushplus = function(title, content, token) {
        let url = `http://www.pushplus.plus/send`
        let data = {
            title,
            content,
            token
        }
        const options = {
            headers: {
            'Content-Type': 'application/json',
            }
        };
        let rsp = http.postJson(url, data, options)
        console.log(rsp.body.string())
    }
    this.sendNotifyMsg = function(title, content, token) {
        this.wxpusher(title, content, token)
        this.storageOp('notifyMsg', true, { msg: '' })
        launch('com.termux')
    }
    this.setFloaty = function(floaty) {
        this.floaty = floaty
    }
    this.setFloatyInfo = function (position, text) {
        if (!this.floaty) return
        if (text == undefined) {
            return
        }
        if (!position) {
            if (this.floaty.hide)
                this.floaty.hide()
            else
                this.floaty.setFloatyInfo({x:100,y:100}, '--')
            return
        }
        position.x += 5
        this.floaty.setFloatyInfo(position, text + ' ' + position.x + ' ' + position.y)
    }
    this.setFloatyInfoEle = function(ele, text) {
        let x = ele.bounds().top
        let y = ele.bounds().left
        x = x > 10? x-10: x
        y = y > 10? y-10: y
        this.setFloatyInfo({x, y}, text)
    }
    this.click = function(x, y, txt) {
        try {
            this.setFloatyInfo(null, '')
        } catch (err) {

        }
        this.logInfo('click', txt, x,y)
        click(x,y)
        this.setFloatyInfo({x,y:y+10}, txt)
    }
    this.boundsInsideElements = function(bounds, text) {        
        let a = bounds.includes?bounds[0]:bounds.left
        let b = bounds.includes?bounds[1]:bounds.top
        let c = bounds.includes?bounds[2]:bounds.right
        let d = bounds.includes?bounds[3]:bounds.bottom
        let lst = textMatches(text).boundsInside(a,b,c,d).find()
        if (!lst) lst = descMatches(text).boundsInside(a,b,c,d).find()
        return lst
    }
    this.boundsInsideText = function(bounds, text) {
        let lst = this.boundsInsideElements(bounds, text)
        let t = ''
        if (!lst) return t
        lst.forEach(e => {
            if (t) t += ' '
            t += e.text()
        })
        return t
    }
    this.findCloseButton = function() {        
        let renwu = this.findTextDescMatchesTimeout(() =>{
            return className('ImageView').find()
        }, 1000)
        if (!renwu) {
            this.logInfo('没找到ImageView')
            return
        }
        renwu.forEach((w) => {
            let left = w.bounds().left
            let top = w.bounds().top 
            let bottom = w.bounds().bottom
            let right = w.bounds().right
            if ((right-left) < 70) {
                let centerXDev = device.width/2
                let centerXEle = w.bounds().centerX()
                if (left > (device.width-150) || (centerXEle > (centerXDev-20) && centerXEle < (centerXDev+20))) {
                    w.click()
                    this.logInfo('关闭按钮', w.bounds())
                }
            }
        })
    }
    this.notificationObj = ''
    this.onNotification = function(notification) {
        this.notificationObj = notification
        this.logInfo('tocast:', notification.getText())
    }
    this.getNotification = function() {
        let t = ''
        if (this.notificationObj) {
            t = this.notificationObj.getText() || ''
            this.notificationObj = null
        }
        return t
    }
    this.turnOnOffPower = function() {
        let url = ''
        if (device.getBattery() > 90 && device.isCharging()) {
            url = 'http://192.168.68.71:386/switch/close'
        }
        if (device.getBattery() < 20 && !device.isCharging()) {
            url = 'http://192.168.68.71:386/switch/open'
        }
        if (url) {
            let r = http.get(url);
            let msg = r.body.string()
            this.logInfo(`${url}: ${msg}`)
        }

    }
}

module.exports = Util

